package handler

import (
	"context"
	"fmt"
	"github.com/golang/protobuf/proto"
	"github.com/golang/protobuf/ptypes/empty"
	"github.com/golang/protobuf/ptypes/wrappers"
	"kop/modules/activity/first_pay"
	"time"

	"kop/framework/broker"
	context2 "kop/framework/context"
	"kop/framework/errors"
	"kop/libs/database"
	"kop/modules/activity/configuration"
	"kop/modules/activity/entity"
	"kop/modules/activity/models"
	configuration2 "kop/modules/item/configuration"
	"kop/modules/item/consts"
	"kop/pb"
	"kop/pb/service"
	"kop/util/date"
	"kop/util/errgroup"

	awardM "kop/modules/award/models"
	guildC "kop/modules/guild/client"
	itemC "kop/modules/item/client"
	payC "kop/modules/pay/client"
	roleC "kop/modules/role/client"
)

type ActivityServiceHandler struct {
	context2.Context
}

func (h *ActivityServiceHandler) Main(ctx context.Context, req *empty.Empty, resp *pb.Activities) (err error) {

	var roleID = h.GetRoleID(ctx)
	var role = pb.Role{RoleID: roleID}
	var waitGroup errgroup.Group

	// 7日登陆
	waitGroup.Go(func() error {

		var res, err = roleC.RoleService.Day7(ctx, req)
		if err == nil {
			for _, v := range res.Day7Awards {
				if v.State != pb.State_Finish {
					resp.Day7Resp = res
					break
				}
			}
		}

		return err
	})

	// 签到
	waitGroup.Go(func() error {

		resp.SignInResp, err = roleC.RoleService.GetSignIn(ctx, req)
		return err
	})

	// 首充
	waitGroup.Go(func() error {

		var pay, err = roleC.RoleService.GetPay(ctx, req)
		if err == nil {

			if !pay.GetFirstPayAward {
				resp.FirstPayResp = first_pay.FirstPayResp(&role)
				if pay.Diamond > 0 {
					resp.FirstPayResp.State = pb.State_Doing
				}
			}
		}

		return err
	})

	// 基金
	waitGroup.Go(func() error {

		resp.ActivityPeerages = &pb.ActivityPeerages{}
		return h.Peerages(ctx, req, resp.ActivityPeerages)
	})

	// 月卡
	waitGroup.Go(func() error {

		resp.MonthCardResp, err = roleC.RoleService.GetMonthCard(ctx, &service.RoleRequest{RoleID: h.GetRoleID(ctx)})
		return err
	})

	// 充值
	waitGroup.Go(func() error {

		resp.Pays = &pb.ActivityPays{}
		return h.Pays(ctx, req, resp.Pays)
	})

	// 限时
	waitGroup.Go(func() error {

		resp.Quests = &pb.ActivityQuests{}
		return h.Quests(ctx, req, resp.Quests)
	})

	// 寻宝
	waitGroup.Go(func() error {

		resp.Treasures = &pb.ActivityBountyList{List: make([]*pb.ActivityBounty, 0)}
		for _, v := range configuration.GetTreasureConfigs(h.GetServerID(ctx)) {

			resp.Treasures.List = append(resp.Treasures.List, &pb.ActivityBounty{
				ID:          v.ActivityID,
				Type:        v.SubType,
				StartTime:   int32(v.BeginTime().Unix()),
				EndTime:     int32(v.EndTime().Unix()),
				BountyAward: &pb.BountyAward{Awards: configuration.GetRankingAwards(&role, v.ActivityID)},
				BountyGuildAward: &pb.BountyGuildAward{
					LeaderAwards: configuration.GetLeaderAwards(v.ActivityID),
					MemberAwards: configuration.GetMemberAwards(v.ActivityID),
				},
			})
		}
		return nil
	})

	return waitGroup.Wait()
}

func (h *ActivityServiceHandler) Peerages(ctx context.Context, _ *empty.Empty, resp *pb.ActivityPeerages) error {

	var role = roleC.GetRole(h.GetRoleID(ctx))

	var data = models.GetActivityPeerage(database.DB, role.RoleID)

	resp.Open = data.Open
	resp.List = make([]*pb.Activity, 0, len(configuration.ActivityPeerageConfigs))
	for _, v := range configuration.ActivityPeerageConfigs {

		var activityAward = pb.Activity{
			ID:    v.Peerage,
			Award: awardM.RandAward(role, v.AwardID),
			State: pb.State_Default,
		}

		if data.Get(v.Peerage) {
			activityAward.State = pb.State_Finish
		} else if data.Open && role.Level >= v.Peerage {
			activityAward.State = pb.State_Doing
		}

		resp.List = append(resp.List, &activityAward)
	}

	return nil
}

func (h *ActivityServiceHandler) OpenPeerage(ctx context.Context, _ *empty.Empty, resp *pb.ActivityPeerages) error {

	var role = roleC.GetRole(h.GetRoleID(ctx))
	if role.VIP < 3 {
		return errors.ParamError
	}

	var data = models.GetActivityPeerage(database.DB, role.RoleID)
	if !data.Open {

		if err := itemC.AsyncDelItem(role.RoleID, h.GetServerID(ctx), consts.Diamond, 1000); err != nil {
			return err
		}
	}

	data.Open = true
	models.SaveActivityPeerage(database.DB, &data)

	resp.Open = data.Open
	resp.List = make([]*pb.Activity, 0, len(configuration.ActivityPeerageConfigs))
	for _, v := range configuration.ActivityPeerageConfigs {

		var activityAward = pb.Activity{
			ID:    v.Peerage,
			Award: awardM.RandAward(role, v.AwardID),
			State: pb.State_Default,
		}

		if data.Get(v.Peerage) {
			activityAward.State = pb.State_Finish
		} else if data.Open && role.Level >= v.Peerage {
			activityAward.State = pb.State_Doing
		}

		resp.List = append(resp.List, &activityAward)
	}

	return nil
}

func (h *ActivityServiceHandler) GetPeerageAward(ctx context.Context, req *wrappers.Int32Value, resp *pb.Award) error {

	var role = roleC.GetRole(h.GetRoleID(ctx))

	var conf, err = configuration.GetByPeerage(req.Value)
	if err != nil {
		return err
	}

	var data = models.GetActivityPeerage(database.DB, role.RoleID)
	if !data.Open {
		return errors.ParamError
	}

	*resp = *awardM.RandAward(role, conf.AwardID)
	if data.Get(req.Value) {
		return nil
	}

	data.Set(req.Value)
	models.SaveActivityPeerage(database.DB, &data)
	return awardM.SendAward(role, resp)
}

// 充值活动数据
func (h *ActivityServiceHandler) Pays(ctx context.Context, _ *empty.Empty, resp *pb.ActivityPays) error {

	var roleID = h.GetRoleID(ctx)

	var daily, total, Day = make([]*pb.Activity, 0), make([]*pb.Activity, 0), make([]*pb.Activity, 0)

	var conf = configuration.GetPayConfig(h.GetServerID(ctx))
	for _, v := range conf.List() {
		switch v.Type {
		case 1:
			daily = append(daily, &pb.Activity{ID: v.ID, Award: awardM.RandAward(&pb.Role{RoleID: roleID}, v.AwardID), Value2: v.Value})
		case 2:
			total = append(total, &pb.Activity{ID: v.ID, Award: awardM.RandAward(&pb.Role{RoleID: roleID}, v.AwardID), Value2: v.Value})
		case 3:
			Day = append(Day, &pb.Activity{ID: v.ID, Award: awardM.RandAward(&pb.Role{RoleID: roleID}, v.AwardID), Value2: v.Value})
		}
	}

	var beginTime = conf.BeginTime()
	var res, err = payC.PayService.Activity(ctx, &wrappers.Int64Value{Value: beginTime.Unix()})
	if err != nil {
		return err
	}

	for _, v := range daily {
		v.Value = int64(res.Daily)
		if v.Value >= v.Value2 {
			v.State = pb.State_Doing
		}
	}
	for _, v := range total {
		v.Value = int64(res.Total)
		if v.Value >= v.Value2 {
			v.State = pb.State_Doing
		}
	}
	for _, v := range Day {
		v.Value = int64(res.Day)
		if v.Value >= v.Value2 {
			v.State = pb.State_Doing
		}
	}

	var data = models.GetPay(database.DB, roleID)
	data.PayData, _ = proto.Marshal(res)
	if data.Date != date.Date(beginTime) {
		data.Date = date.Date(beginTime)
		data.Init()
	}

	// 保存充值数据 后面领奖时用
	models.SavePay(database.DB, &data)

	var d = date.Date(time.Now())
	for _, v := range daily {
		if data.Get(fmt.Sprintf("%d_%d", d, v.ID)) {
			v.State = pb.State_Finish
		}
	}
	for _, v := range total {
		if data.Get(fmt.Sprintf("total_%d", v.ID)) {
			v.State = pb.State_Finish
		}
	}
	for _, v := range Day {
		if data.Get(fmt.Sprintf("day_%d", v.ID)) {
			v.State = pb.State_Finish
		}
	}

	*resp = pb.ActivityPays{
		Daily:     daily,
		Total:     total,
		Day:       Day,
		StartTime: int32(beginTime.Unix()),
		EndTime:   int32(conf.EndTime().Unix()),
	}

	return nil
}

// 领取充值活动奖励
func (h *ActivityServiceHandler) GetPayAward(ctx context.Context, req *wrappers.Int32Value, resp *pb.Award) error {

	var roleID = h.GetRoleID(ctx)

	for _, conf := range configuration.GetPayConfig(h.GetServerID(ctx)).List() {
		if conf.ID == req.Value {

			var data = models.GetPay(database.DB, roleID)
			var mess service.PayActivityResp
			_ = proto.Unmarshal(data.PayData, &mess)

			var key = ""
			var n int32 = 0
			switch conf.Type {
			case 1:
				key = fmt.Sprintf("%d_%d", date.Date(time.Now()), conf.ID)
				n = mess.Daily

			case 2:
				key = fmt.Sprintf("total_%d", conf.ID)
				n = mess.Total

			case 3:
				key = fmt.Sprintf("day_%d", conf.ID)
				n = mess.Day
			}

			if int64(n) < conf.Value { // 充值数量不够
				return errors.ParamError
			}

			if data.Get(key) {
				return nil
			}

			data.Set(key)
			models.SavePay(database.DB, &data)

			var role = pb.Role{RoleID: roleID}
			*resp = *awardM.RandAward(&role, conf.AwardID)
			return awardM.SendAward(&role, resp)

		}
	}

	return errors.ParamError
}

func (h *ActivityServiceHandler) Quests(ctx context.Context, _ *empty.Empty, resp *pb.ActivityQuests) error {

	var roleID = h.GetRoleID(ctx)

	var conf = configuration.GetQuestConfig(h.GetServerID(ctx))
	var beginTime = conf.BeginTime()

	resp.Quests = make(map[int32]*pb.ActivityList)
	resp.StartTime = int32(beginTime.Unix())
	resp.EndTime = int32(conf.EndTime().Unix())

	var data = models.GetQuest(database.DB, roleID)
	if data.Date != date.Date(beginTime) {
		data.Init(date.Date(beginTime))
		models.SaveQuest(database.DB, &data)
	}

	for _, v := range conf.List() {

		if _, ok := resp.Quests[v.Type]; !ok {
			resp.Quests[v.Type] = &pb.ActivityList{List: make([]*pb.Activity, 0)}
		}

		var act = pb.Activity{
			ID:     v.ID,
			Value:  data.GetValue(v.Type),
			Value2: v.Value,
			Award:  awardM.RandAward(&pb.Role{RoleID: roleID}, v.AwardID),
		}

		if data.IsFinish(v.ID) {
			act.State = pb.State_Finish
		} else if act.Value >= act.Value2 {
			act.State = pb.State_Doing
		}

		var list = resp.Quests[v.Type]
		list.List = append(list.List, &act)
	}

	return nil
}

// 领取充值活动奖励
func (h *ActivityServiceHandler) GetQuestAward(ctx context.Context, req *wrappers.Int32Value, resp *pb.Award) error {

	var roleID = h.GetRoleID(ctx)

	for _, conf := range configuration.GetQuestConfig(h.GetServerID(ctx)).List() {
		if conf.ID == req.Value {
			var data = models.GetQuest(database.DB, roleID)

			if data.IsFinish(req.Value) {
				return nil
			}
			if data.GetValue(conf.Type) < conf.Value {
				return errors.ParamError
			}

			data.SetFinish(req.Value)
			models.SaveQuest(database.DB, &data)

			var role = pb.Role{RoleID: roleID}
			*resp = *awardM.RandAward(&role, conf.AwardID)
			return awardM.SendAward(&role, resp)
		}
	}

	return errors.ParamError
}

// only power and income activity
//func (h *ActivityServiceHandler) SetPoints(_ context.Context, req *service.ActivityPointsRequest, _ *empty.Empty) error {
//
//	var beginTime = configuration.GetQuestConfig(req.ServerID).BeginTime()
//
//	if req.Type == 7 { // 7 = TypePower 11
//		var data = models.GetQuest(database.DB, req.RoleID)
//		if data.Date != date.Date(beginTime) {
//			data.Init(date.Date(beginTime), roleC.GetMaxPower(req.RoleID))
//		}
//
//		data.SetValue(req.Type, req.Points-data.InitPower)
//		models.SaveQuest(database.DB, &data)
//
//		_ = broker.RolePublish(req.RoleID, pb.WsCode_CodeActivity, &pb.CodeActivityData{Type: req.Type, Value: data.GetValue(req.Type)})
//	}
//
//	for _, v := range configuration.GetRankingConfigs(req.ServerID) {
//
//		if v.SubType == req.Type && v.InTime() {
//
//			switch v.SubType {
//			case 7: // 7 = TypePower
//				var data = h.InitRanking(req.RoleID, req.ServerID, v.ActivityID, date.Date(v.BeginTime()), roleC.GetMaxPower(req.RoleID))
//				data.Points = req.Points - data.InitValue
//				models.SaveRanking(database.DB, data)
//			case 11: // 11 = TypeIncome
//				var data = h.InitRanking(req.RoleID, req.ServerID, v.ActivityID, date.Date(v.BeginTime()), moneyC.GetIncome(req.RoleID))
//				data.Points = req.Points - data.InitValue
//				models.SaveRanking(database.DB, data)
//			}
//
//		}
//	}
//
//	return nil
//}

func (h *ActivityServiceHandler) Bounty(ctx context.Context, _ *empty.Empty, resp *pb.ActivityBountyList) error {

	var role, serverID, guildID = pb.Role{RoleID: h.GetRoleID(ctx)}, h.GetServerID(ctx), h.GetGuildID(ctx)
	resp.List = make([]*pb.ActivityBounty, 0)

	for _, v := range configuration.GetRankingConfigs(serverID) {

		var myRanking = models.GetMyRanking(database.DB, role.RoleID, v.ActivityID, date.Date(v.BeginTime()))

		resp.List = append(resp.List, &pb.ActivityBounty{
			ID:        v.ActivityID,
			Type:      v.SubType,
			StartTime: int32(v.BeginTime().Unix()),
			EndTime:   int32(v.EndTime().Unix()),
			ShopID2:   v.ShopID,
			BountyAward: &pb.BountyAward{
				Awards: configuration.GetRankingAwards(&role, v.ActivityID),
				Ok:     myRanking != nil && myRanking.Get,
			},
		})
	}

	var member *pb.GuildMember
	var err error
	if guildID > 0 {
		if member, err = guildC.GetMember(role.RoleID, serverID, guildID); err != nil {
			return err
		}
	}

	for _, v := range configuration.GuildRankingConfigs(serverID) {

		var mess = pb.ActivityBounty{
			ID:        v.ActivityID,
			Type:      v.SubType,
			StartTime: int32(v.BeginTime().Unix()),
			EndTime:   int32(v.EndTime().Unix()),
			//ShopID1:   8, // 固定为钻石商店
			ShopID2: v.ShopID,
			BountyGuildAward: &pb.BountyGuildAward{
				LeaderAwards: configuration.GetLeaderAwards(v.ActivityID),
				MemberAwards: configuration.GetMemberAwards(v.ActivityID),
			},
		}

		if guildID > 0 {

			if data := models.GetGuildRanking(v.ActivityID, guildID); data != nil {
				mess.BountyGuildAward.LeaderOk = data.LeaderR // 会长是否领奖
				if member.Position != pb.GuildPosition_President {
					_, mess.BountyGuildAward.MemberOk = data.Records[role.RoleID] // 成员是否领奖
				}
			}
		}

		resp.List = append(resp.List, &mess)
	}

	return nil
}

func (h *ActivityServiceHandler) Ranking(ctx context.Context, req *wrappers.Int32Value, resp *pb.ActivityRankingResp) error {

	var serverID = h.GetServerID(ctx)
	var conf *configuration.ActivityConf
	for _, v := range configuration.GetRankingConfigs(serverID) {
		if v.ActivityID == req.Value {
			conf = &v
			break
		}
	}

	if conf == nil {
		for _, v := range configuration.GetTreasureConfigs(serverID) {
			if v.ActivityID == req.Value {
				conf = &v
				break
			}
		}
	}

	if conf == nil {
		return errors.ParamError
	}

	var where = entity.Ranking{ActivityID: req.Value, ServerID: h.GetServerID(ctx), Date: date.Date(conf.BeginTime())}

	var awardsConfigs = configuration.GetAwardsByActivityID(req.Value)
	var limit = awardsConfigs[len(awardsConfigs)-1].RankMax

	var data []entity.Ranking
	database.DB.Where(where).Order("points DESC").Order("updated_at ASC").Limit(limit).Find(&data)

	var roleIDs = make([]int32, 0, len(data))
	for _, v := range data {
		roleIDs = append(roleIDs, v.RoleID)
	}

	var roleID = h.GetRoleID(ctx)
	var roles = roleC.GetRoles(roleIDs)

	resp.Ranking = make([]*pb.Ranking, 0, len(data))
	for k, v := range data {
		resp.Ranking = append(resp.Ranking, &pb.Ranking{Role: roles[v.RoleID], Number: int32(k) + 1, Points: v.Points})

		if v.RoleID == roleID {
			//resp.Ok = v.Get
			resp.MyRanking = &pb.RankingNumber{
				Number: int32(k) + 1,
				Points: v.Points,
			}
		}
	}

	if resp.MyRanking == nil {
		if myRanking := models.GetMyRanking(database.DB, roleID, req.Value, date.Date(conf.BeginTime())); myRanking != nil {

			var c int32 = 0
			database.DB.Table(myRanking.TableName()).Where(where).Where("points > ?", myRanking.Points).Count(&c)
			//resp.Ok = myRanking.Get

			resp.MyRanking = &pb.RankingNumber{
				Number: c + 1,
				Points: myRanking.Points,
			}
		}
	}

	return nil
}

func (h *ActivityServiceHandler) GetRankingAward(ctx context.Context, req *wrappers.Int32Value, resp *pb.Award) error {

	var serverID = h.GetServerID(ctx)
	var conf *configuration.ActivityConf
	for _, v := range configuration.GetRankingConfigs(serverID) {
		if v.ActivityID == req.Value {
			conf = &v
			break
		}
	}

	if conf == nil {
		for _, v := range configuration.GetTreasureConfigs(serverID) {
			if v.ActivityID == req.Value {
				conf = &v
				break
			}
		}
	}

	if conf == nil {
		return errors.ParamError
	}

	var roleID = h.GetRoleID(ctx)
	var myRanking = models.GetMyRanking(database.DB, roleID, req.Value, date.Date(conf.BeginTime()))
	if myRanking == nil {
		return errors.ParamError
	}
	if myRanking.Get {
		return nil
	}

	var awardsConfigs = configuration.GetAwardsByActivityID(req.Value)
	var limit = awardsConfigs[len(awardsConfigs)-1].RankMax

	var data []entity.Ranking
	var where = entity.Ranking{ActivityID: req.Value, ServerID: h.GetServerID(ctx), Date: date.Date(conf.BeginTime())}
	database.DB.Where(where).Order("points DESC").Order("updated_at ASC").Limit(limit).Find(&data)

	for k, v := range data {

		if v.RoleID == roleID {

			for _, r := range awardsConfigs {

				if k+1 <= r.RankMax {

					myRanking.Get = true
					models.SaveRanking(database.DB, myRanking)

					var role = pb.Role{RoleID: roleID}
					*resp = *awardM.RandAward(&role, r.AwardID)
					return awardM.SendAward(&role, resp)
				}
			}
		}
	}

	return errors.ParamError
}

func (h *ActivityServiceHandler) TreasGuildRanking(ctx context.Context, req *wrappers.Int32Value, resp *pb.GuildRankingResp) error {

	var serverID = h.GetServerID(ctx)
	for _, conf := range configuration.GetTreasureConfigs(serverID) {

		if conf.ActivityID == req.Value {

			var guildID = h.GetGuildID(ctx)
			var thisDate = date.Date(conf.BeginTime())

			var where = entity.TreasGuildRanking{ServerID: serverID, Date: thisDate}

			var awardsConfigs = configuration.GetAwardsByActivityID(conf.ActivityID)
			var limit = awardsConfigs[len(awardsConfigs)-1].RankMax

			var data []entity.TreasGuildRanking
			database.DB.Where(where).Order("score DESC").Order("updated_at ASC").Limit(limit).Find(&data)

			resp.Ranking = make([]*pb.GuildRanking, len(data))
			for k, v := range data {
				resp.Ranking[k] = &pb.GuildRanking{
					Name:  v.Name,
					Flag:  v.Flag,
					Level: v.Level,
					Rank:  int32(k) + 1,
					Score: v.Score,
				}

				if guildID > 0 && v.GuildID == guildID {
					resp.MyRank = &pb.GuildRank{
						Rank:  int32(k) + 1,
						Score: v.Score,
					}
				}
			}

			if resp.MyRank == nil && guildID > 0 {
				if myRank := models.GetTreasGuildRanking(guildID); myRank != nil && myRank.Date == thisDate {

					var c int32 = 0
					database.DB.Model(myRank).Where(where).Where("score > ?", myRank.Score).Count(&c)
					resp.MyRank = &pb.GuildRank{
						Rank:  c + 1,
						Score: myRank.Score,
					}
				}
			}
		}
	}

	return nil
}

func (h *ActivityServiceHandler) PlayTreasure(ctx context.Context, req *wrappers.Int32Value, resp *pb.PointsAward) error {

	var itemConf, ok = configuration.TreasureItemConfigs[req.Value]
	if !ok {
		return errors.ParamError
	}

	for _, v := range configuration.GetTreasureConfigs(h.GetServerID(ctx)) {
		if v.SubType == itemConf.Type {

			var roleID, serverID = h.GetRoleID(ctx), h.GetServerID(ctx)
			if err := itemC.AsyncDelItem(roleID, serverID, itemConf.ItemID, 1); err != nil {
				return err
			}

			if v.InTime() {

				var thisDate = date.Date(v.BeginTime())
				resp.Points = itemConf.Score
				var myRanking = h.initRanking(roleID, serverID, v.ActivityID, thisDate)
				myRanking.Points += resp.Points
				models.SaveRanking(database.DB, myRanking)

				// 公会加分
				if guildID := h.GetGuildID(ctx); guildID > 0 {
					_ = InitTreasGuildRanking(guildID, serverID, thisDate)
					_ = models.AddTreasGuildScore(guildID, resp.Points)
				}
			}

			var role = roleC.GetRole(roleID)
			resp.Award = awardM.RandAward(role, itemConf.AwardID)

			if err := awardM.SendAward(role, resp.Award); err != nil {
				return err
			}

			for _, v := range resp.Award.AwardItems {
				if v.RawItem.ItemID != consts.Treasure && configuration2.GetByItemID(v.RawItem.ItemID).Quality > 2 {

					var msg = entity.TreasMessage{
						ServerID: serverID,
						Name:     role.Name,
						RoleID:   role.RoleID,
						ItemID1:  req.Value,
						ItemID2:  v.RawItem.ItemID,
					}

					models.CreateTreasMessage(&msg)
					_ = broker.RoomPublish("treas", serverID, pb.WsCode_CodeTreasMsg, buildPbTreasMsg(msg))
					break
				}
			}

			return nil
		}
	}

	return errors.ParamError
}

func (h *ActivityServiceHandler) TreasMessages(ctx context.Context, _ *empty.Empty, resp *pb.TreasMessages) error {

	var data []entity.TreasMessage
	database.DB.Where("server_id = ?", h.GetServerID(ctx)).Order("id DESC").Limit(20).Find(&data)

	resp.Messages = make([]*pb.TreasMsg, 0, len(data))
	for _, v := range data {
		resp.Messages = append(resp.Messages, buildPbTreasMsg(v))
	}

	return nil
}

func (h *ActivityServiceHandler) GuildRanking(ctx context.Context, req *wrappers.Int32Value, resp *pb.GuildRankingResp) error {

	var conf configuration.ActivityConf

	for _, v := range configuration.GuildRankingConfigs(h.GetServerID(ctx)) {
		if v.ActivityID == req.Value {
			conf = v
		}
	}

	if conf.ActivityID == 0 {
		return errors.ParamError
	}

	var guildID = h.GetGuildID(ctx)
	var thisDate = date.Date(conf.BeginTime())

	var where = entity.GuildRanking{ServerID: h.GetServerID(ctx), Date: thisDate, ActivityID: conf.ActivityID}

	var awardsConfigs = configuration.GetAwardsByActivityID(conf.ActivityID)
	var limit = awardsConfigs[len(awardsConfigs)-1].RankMax

	var data []entity.GuildRanking
	database.DB.Where(where).Order("score DESC").Order("updated_at ASC").Limit(limit).Find(&data)

	resp.Ranking = make([]*pb.GuildRanking, len(data))
	for k, v := range data {
		resp.Ranking[k] = &pb.GuildRanking{
			Name:  v.Name,
			Flag:  v.Flag,
			Level: v.Level,
			Rank:  int32(k) + 1,
			Score: v.Score,
		}

		if guildID > 0 && v.GuildID == guildID {
			resp.MyRank = &pb.GuildRank{
				Rank:  int32(k) + 1,
				Score: v.Score,
			}
		}
	}

	if resp.MyRank == nil && guildID > 0 {
		if myRank := models.GetGuildRanking(conf.ActivityID, guildID); myRank != nil && myRank.Date == thisDate {

			var c int32 = 0
			database.DB.Model(myRank).Where(where).Where("score > ?", myRank.Score).Count(&c)
			resp.MyRank = &pb.GuildRank{
				Rank:  c + 1,
				Score: myRank.Score,
			}
		}
	}

	return nil
}

func (h *ActivityServiceHandler) GetGuildRankingAward(ctx context.Context, req *wrappers.Int32Value, resp *pb.Award) error {

	var serverID, guildID = h.GetServerID(ctx), h.GetGuildID(ctx)
	if guildID == 0 {
		return errors.ParamError
	}

	var conf *configuration.ActivityConf
	for _, v := range configuration.GuildRankingConfigs(serverID) {
		if v.ActivityID == req.Value {
			conf = &v
			break
		}
	}

	if conf == nil {
		for _, v := range configuration.GetTreasureConfigs(serverID) {
			if v.ActivityID == req.Value {
				conf = &v
				break
			}
		}
	}

	if conf == nil {
		return errors.ParamError
	}

	var roleID = h.GetRoleID(ctx)

	var myRank pb.GuildRankingResp

	switch conf.Type {
	case configuration.TypeTreasure:
		if err := h.TreasGuildRanking(ctx, nil, &myRank); err != nil {
			return err
		}
	default:
		if err := h.GuildRanking(ctx, req, &myRank); err != nil {
			return err
		}
	}

	if myRank.MyRank == nil {
		return errors.ParamError
	}

	for _, r := range configuration.GetAwardsByActivityID(conf.ActivityID) {

		if int(myRank.MyRank.Rank) <= r.RankMax {

			switch conf.Type {
			case configuration.TypeTreasure:
				var myRanking = models.GetTreasGuildRanking(guildID)
				myRanking.Records[roleID] = 1
				models.SaveTreasGuildRanking(myRanking)

			default:

				var myRanking = models.GetGuildRanking(conf.ActivityID, guildID)
				myRanking.Records[roleID] = 1
				models.SaveGuildRanking(myRanking)

			}

			member, err := guildC.GetMember(roleID, serverID, guildID)
			if err != nil {
				return err
			}

			var role = pb.Role{RoleID: roleID}

			switch member.Position {
			case pb.GuildPosition_President:

				*resp = *awardM.RandAward(&role, r.LeaderAwardID)
			default:

				*resp = *awardM.RandAward(&role, r.MemberAwardID)
			}

			return awardM.SendAward(&role, resp)
		}
	}

	return errors.ParamError
}

func (h *ActivityServiceHandler) AddPoints(_ context.Context, req *service.ActivityPointsRequest, _ *empty.Empty) error {

	var conf = configuration.GetQuestConfig(req.ServerID)
	var beginDate = date.Date(conf.BeginTime())

	if req.Type <= 9 {
		var data = models.GetQuest(database.DB, req.RoleID)
		if data.Date != beginDate {
			data.Init(beginDate)
		}

		data.AddValue(req.Type, req.Points)
		models.SaveQuest(database.DB, &data)

		_ = broker.RolePublish(req.RoleID, pb.WsCode_CodeActivity, &pb.CodeActivityData{Type: req.Type, Value: data.GetValue(req.Type)})
	}

	for _, v := range configuration.GetRankingConfigs(req.ServerID) {

		if v.SubType == req.Type && v.InTime() {
			h.initRanking(req.RoleID, req.ServerID, v.ActivityID, date.Date(v.BeginTime()))
			models.UpdatePoints(database.DB, req.RoleID, v.ActivityID, req.Points)
		}
	}

	if guild, _ := guildC.MyGuild(req.RoleID, req.ServerID, 0); guild != nil {

		for _, v := range configuration.GuildRankingConfigs(req.ServerID) {
			if v.SubType == req.Type && v.InTime() {

				_ = initGuildRanking(guild, v.ActivityID, date.Date(v.BeginTime()))
				_ = models.AddGuildScore(v.ActivityID, guild.GuildID, req.Points)
			}
		}
	}

	return nil
}

func (h *ActivityServiceHandler) AddGuildPoints(_ context.Context, req *service.GuildPointsRequest, _ *empty.Empty) error {

	for _, v := range configuration.GuildRankingConfigs(req.Guild.ServerID) {
		if v.SubType == req.Type && v.InTime() {

			_ = initGuildRanking(req.Guild, v.ActivityID, date.Date(v.BeginTime()))
			_ = models.AddGuildScore(v.ActivityID, req.Guild.GuildID, req.Points)
		}
	}

	return nil
}

func InitTreasGuildRanking(guildID, serverID, date int32) error {

	var data = models.GetTreasGuildRanking(guildID)
	if data == nil {

		var guild, err = guildC.GetGuild(serverID, guildID)
		if err != nil {
			return err
		}

		data = &entity.TreasGuildRanking{
			GuildID:  guildID,
			Name:     guild.Name,
			Flag:     guild.Flag,
			Level:    guild.Level,
			ServerID: guild.ServerID,
			Date:     date,
			//Score:    0,
			//Records:   nil,
		}

		return database.DB.Create(data).Error
	} else if data.Date != date {

		data.Date = date
		data.Score = 0
		data.Records = make(map[int32]int)
		data.CreatedAt = time.Now()
		return database.DB.Save(data).Error
	}

	return nil
}

func initGuildRanking(guild *pb.Guild, activityID, date int32) error {

	var data = models.GetGuildRanking(activityID, guild.GuildID)
	if data == nil {

		data = &entity.GuildRanking{
			GuildID:    guild.GuildID,
			ActivityID: activityID,
			Name:       guild.Name,
			Flag:       guild.Flag,
			Level:      guild.Level,
			ServerID:   guild.ServerID,
			Date:       date,
			//Score:    0,
			//Records:   nil,
		}

		return database.DB.Create(data).Error
	} else if data.Date != date {

		data.Date = date
		data.Score = 0
		data.Records = make(map[int32]int)
		data.CreatedAt = time.Now()
		return database.DB.Save(data).Error
	}

	return nil
}

func (h *ActivityServiceHandler) initRanking(roleID, serverID, activityID, date int32) *entity.Ranking {

	var data = models.GetMyRanking(database.DB, roleID, activityID, date)
	if data == nil {
		data = &entity.Ranking{
			RoleID:     roleID,
			ActivityID: activityID,
			ServerID:   serverID,
			Date:       date,
			//InitValue:  initValue,
		}
		models.CreateRanking(database.DB, data)
	}

	if data.Date != date {
		if data.Date != date {
			data.Date = date
			data.Points = 0
			//data.InitValue = initValue
			data.Get = false
			data.CreatedAt = time.Now()
			models.SaveRanking(database.DB, data)
		}
	}

	return data
}

func buildPbTreasMsg(data entity.TreasMessage) *pb.TreasMsg {
	return &pb.TreasMsg{
		Name:      data.Name,
		ItemID1:   data.ItemID1,
		ItemID2:   data.ItemID2,
		Timestamp: data.CreatedAt.Unix(),
	}
}
